#pragma once

#ifndef _CORE_CLIENT_CONNECTION_H_
#define _CORE_CLIENT_CONNECTION_H_

#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/SharedPtr.h"
#include "Poco/BasicEvent.h"
#include "Poco/Event.h"
#include "Poco/DOM/Document.h"

namespace ExamSystem
{
    using Poco::Net::SocketAddress;
    using Poco::Net::StreamSocket;
    using Poco::SharedPtr;
    using Poco::BasicEvent;
    using Poco::Event;
    using Poco::XML::Document;

    class CXMLConnection;
    class CCoreXMLHandlerManager;

    /**************************************************************************\
     Component:     CExamClientConnection
     Description:   
        This class manages a connection to the server
    \**************************************************************************/
    class CExamClientConnection
    {
    public:
        CExamClientConnection(void);
        ~CExamClientConnection(void);

    public:
        // set socket address and port
        void SetServerAddress(const std::string &host, Poco::UInt16 port);
        void SetServerAddress(const SocketAddress &socketAddress);

        // try to connect the server, return true when success
        // the server address must be set before connecting
        bool ConnectServer(void);

        // disconnect this connection and re-connect
        bool ReconnectServer(void);

        // disconnect server
        void DisconnectServer(bool wait = true);

        // send xml stanza to the server
        bool SendXMLStanza(Document &xmlStanza);

        // send raw byte to the server
        bool SendRawByte(const void *data, int length);

        // get the xml handlers' manager
        SharedPtr<CCoreXMLHandlerManager> &GetXMLHandlerManager(void);

        // get the connection
        SharedPtr<CXMLConnection> &GetXMLConnection(void);

    protected:
        // event handlers
        void OnConnectionClosed(const void* pSender, int &id);

    public:
        // events
        // connection closed
        BasicEvent<int> eventConnectionClosed;
        // connection disconnected, we will try to reconnect
        BasicEvent<int> eventConnectionDisconnected;
        BasicEvent<int> eventConnectionReconnected;

    protected:
        // the server's address
        SocketAddress m_serverAddress;

        // the client socket
        SharedPtr<StreamSocket> m_clientSocket;

        // the xml connection
        SharedPtr<CXMLConnection> m_xmlConnection;
        // the common xml handlers
        SharedPtr<CCoreXMLHandlerManager> m_xmlHandlerManager;

        // dead connections
        SharedPtr<StreamSocket> m_deadClientSocket;
        SharedPtr<CXMLConnection> m_deadXmlConnection;

        // this flag identifies that the close operation is initiated voluntarily
        // auto reconnecting will be performed if this flag is false
        bool m_flagClosingConnection;

        bool m_flagReconnecting;

        // this object is used to wait in a disconnecting operation
        Event m_synDisconnecting;
    };

}

#endif